インフラエンジニアに贈るAmazon VPC入門 #4 インターネット接続(後編)
シリーズの目次は<a href="/series/vpcfor-infra-engineer/">こちら</a><br>
<a href="/cloud/vpcfor-infra-engineer-3/">前回</a>からだいぶ間があいてしまいましたが、GW中に記事を書く時間がとれたので続編書きます!!
前回のあらすじ
前回は、VPCからインターネットに接続するための機能をご紹介ということで、インターネットゲートウェイとElastic IPを紹介しました。ざっくり以下にまとめます。
- VPC→インターネット : インターネットゲートウェイ経由で接続できる(ただしIPマスカレードはないため、インターネット→VPCへの接続はできない)
- インターネット→VPC : Elastic IPをインターネットゲートウェイで持ち、Static NATを構成して仮想マシンにトラフィックを転送する
Elastic IP(Static NAT)はインターネットに公開するサーバー向け、今回紹介するNATインスタンスは、仮想マシンからインターネットに接続するクライアント向けとご紹介しました。では、NATインスタンスでどのようにインターネット接続を提供するのか、見ていきましょう。
NATインスタンスの動作
NATインスタンスは、IPマスカレードによってVPCの仮想マシンにインターネット接続を提供します。実際の動作は、仮想ルーター、Elastic IPを組み合わせる複雑な動きになります。
仮想マシンからNATインスタンスを介してインターネットに接続する一連の動きを、以下に示します。
- 仮想マシンのルーティングテーブルにより、デフォルトゲートウェイの仮想ルーターにトラフィックを転送
- 仮想マシンの所属するVPCサブネットのルーティングテーブルにより、仮想ルーターがNATインスタンスにトラフィックを転送
- NATインスタンスでIPマスカレード処理を実行(送信元IPアドレスをNATインスタンスのIPアドレスに変更)
- NATインスタンスのルーティングテーブルにより、デフォルトゲートウェイの仮想ルーターにトラフィックを転送
- NATインスタンスの所属するVPCサブネットのルーティングテーブルにより、仮想ルーターがインターネットゲートウェイにトラフィックを転送
- インターネットゲートウェイでStatic NAT処理を実行(送信元IPアドレスをNATインスタンスのEIPに変更)
- インターネットゲートウェイがインターネットの接続先にトラフィックを転送
個人的には、このNATインスタンスの実装は、あまり好きではありません。動きがややこしいですし、ユーザーが自分でNATインスタンスの管理をしなければならないのも煩雑な印象を受けます。VPCのネットワークサービスの一つとして提供される機能であれば、ユーザーからはなるべく抽象化され仮想マシンとして意識されないようにするべきと考えます。
ただ、ユーザーから仮想マシンとして見える分、機能・実装が具体的に把握できる点やカスタマイズ性が高い点は良いとも思っています。
NATインスタンスの実装とカスタマイズ
NATインスタンスの実装
一言で言ってしまうと、仮想マシンでは、Linuxパケットフィルタ(iptables)のNATテーブルでIPマスカレードを動作させています。 例として、標準のNATインスタンス(Amazonの仮想マシンイメージ(AMI)として提供)のコマンドの実行結果を紹介します。
[ec2-user@ip-XX-XX-XX-XX ~]$ sudo iptables -t nat -L -v -n Chain PREROUTING (policy ACCEPT 1 packets, 64 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 30 packets, 2443 bytes) pkts bytes target prot opt in out source destination Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 30 2443 MASQUERADE all -- * eth0 XX.XX.0.0/16 0.0.0.0/0
IPマスカレードが動作している様子がわかります。一般的なLinuxルーターと雰囲気が異なるのは、NATインスタンスには仮想NIC(ENI)が1つしか構成されないため、outのインターフェース名ではなくsourceのネットワークアドレス(実行例では、NATインスタンスの所属するVPCサブネットのアドレス)でIPマスカレードの対象を特定しているところでしょうか。
また、OS起動時のこのルールの追加は割と原始的な仕組みで、RedHat系ディストリビューションでのiptablesのお作法(/etc/sysconfig/iptablesファイル)ではなく、/etc/rc.localファイルからiptablesコマンドを叩くスクリプトを呼び出すようになっています。
- /etc/rc.local
#!/bin/sh # # This script will be executed *after* all the other init scripts. # You can put your own initialization stuff in here if you don't # want to do the full Sys V style init stuff. touch /var/lock/subsys/local # Configure PAT /usr/local/sbin/configure-pat.sh
- /usr/local/sbin/configure-pat.sh
#!/bin/bash # Configure the instance to run as a Port Address Translator (PAT) to provide # Internet connectivity to private instances. # set -x echo "Determining the MAC address on eth0" ETH0_MAC=`/sbin/ifconfig | /bin/grep eth0 | awk '{print tolower($5)}' | grep '^[0-9a-f]\{2\}\(:[0-9a-f]\{2\}\)\{5\}$'` if [ $? -ne 0 ] ; then echo "Unable to determine MAC address on eth0" | logger -t "ec2" exit 1 fi echo "Found MAC: ${ETH0_MAC} on eth0" | logger -t "ec2" VPC_CIDR_URI="http://169.254.169.254/latest/meta-data/network/interfaces/macs/${ETH0_MAC}/vpc-ipv4-cidr-block" echo "Metadata location for vpc ipv4 range: ${VPC_CIDR_URI}" | logger -t "ec2" VPC_CIDR_RANGE=`curl --retry 3 --retry-delay 0 --silent --fail ${VPC_CIDR_URI}` if [ $? -ne 0 ] ; then echo "Unable to retrive VPC CIDR range from meta-data. Using 0.0.0.0/0 instead. PAT may not function correctly" | logger -t "ec2" VPC_CIDR_RANGE="0.0.0.0/0" else echo "Retrived the VPC CIDR range: ${VPC_CIDR_RANGE} from meta-data" |logger -t "ec2" fi echo 1 > /proc/sys/net/ipv4/ip_forward && \ echo 0 > /proc/sys/net/ipv4/conf/eth0/send_redirects && \ /sbin/iptables -t nat -A POSTROUTING -o eth0 -s ${VPC_CIDR_RANGE} -j MASQUERADE if [ $? -ne 0 ] ; then echo "Configuration of PAT failed" | logger -t "ec2" exit 0 fi echo "Configuration of PAT complete" |logger -t "ec2" exit 0 [ec2-user@ip-XX-XX-XX-XX etc]$
それからもう一つ、注意するべき設定としてAWS特有のSource/Dest. Checkがあります。仮想マシンが送受信するトラフィックの宛て先IPアドレス、送信元IPアドレスをチェックし、仮想マシンのIPアドレスでなければフィルタするはたらきを持ちます *1。既定値がEnable(有効)なので、NATインスタンスとして使用するためにはDisable(無効)に変更する必要があります。
NATインスタンスのT具体的な構築手順は、横田さんの記事をご覧ください。
カスタマイズ
IPマスカレードの機能を提供しSource/Dest. CheckをDisableにすれば、好みの仮想マシン(EC2インスタンス)をNATインスタンスとして使うことも可能です。また、AWSの他の機能と組み合わせる構成もアリです。先人の実装例を以下に示します。
-
suz-lab - blog: VPCのNATインスタンスを作ってみる(Squid編)
この記事では、仮想マシンがアクセスできるインターネットのホストを制限するためにIPマスカレードの代替としてSquidで実装しています。アクセス制限だけでなく、Squidのキャッシュを活用するのもいいかもしれません。 -
NATインスタンスを冗長構成にしてみた - log4moto
こちらは、NATインスタンスがインターネット接続のSPOF(単一障害点)になることの対応策として、NATインスタンスの冗長化と監視の仕組みを追加した構成です。
まとめと次回予告
今回は、仮想マシンにインターネット接続を提供する仕組みとして、NATインスタンスの動作、実装を紹介しました。NATインスタンス自体はただのLinuxなので、簡単に実装を確認したり、必要に応じてカスタマイズができることを理解いただけたのではないでしょうか。
次回は先送りになっていました、DNSを取り上げます!
脚注
- Linux OSで言うところのnet.ipv4.ip_forwardを、仮想マシンの外部から制御するイメージです。 ↩